<template>
  <el-table
    ref="tableRef"
    :data="data"
    :max-height="maxHeight"
    :stripe="stripe"
    :border="border"
    style="width: 100%"
    :row-key="rowKey"
    :empty-text="emptyText"
    :highlight-current-row="highlightCurrentRow"
    @current-change="handleCurrentChange"
    @selection-change="handleSelection"
  >
    <el-table-column
      v-if="showSelection"
      type="selection"
      align="center"
      width="60"
    />
    <el-table-column
      v-if="showIndex"
      type="index"
      label="序号"
      align="center"
      width="60"
    />
    <el-table-column
      v-for="item in tableColumn"
      :key="item.label"
      :prop="item.prop"
      :label="item.label"
      :sortable="item.unSortable?false:true"
      :width="item.width?item.width:''"
      :min-width="item.minWidth?item.minWidth:''"
      :class-name="item.className"
      :align="item.align"
      :fixed="item.fixed"
    >
      <template slot-scope="scope">
        <!-- 编辑input  -->
        <template v-if="scope.row.edit && item.edit">
          <!-- 数字输入框 -->
          <el-input
            v-if="item.validateType&&(item.validateType==='number')"
            v-model.number="scope.row[item.prop]"
            :maxlength="item.maxLength"
            class="edit-input"
            size="mini"
            @input="handleChange(scope.row,item)"
          >
            <i
              v-show="item.isRequired && !item.validate"
              slot="suffix"
              :title="item.errorMsg"
              class="el-input__icon el-icon-warning"
            />
          </el-input>
          <!-- 下拉框 -->
          <el-select
            v-else-if="item.validateType&&(item.validateType==='select')"
            v-model="scope.row[item.prop]"
            class="edit-input"
            size="mini"
            @change="handleChange(scope.row,item)"
          >
            <el-option
              v-for="(selectData,j) in item.selectList"
              :key="j"
              :value="selectData.value"
              :label="selectData.label"
            />
            <i
              v-show="item.isRequired && !item.validate"
              slot="prefix"
              :title="item.errorMsg"
              class="el-input__icon el-icon-warning"
            />
          </el-select>
          <!-- 其他输入框 -->
          <el-input
            v-else
            v-model.trim="scope.row[item.prop]"
            :maxlength="item.maxLength"
            class="edit-input"
            size="mini"
            @input="handleChange(scope.row,item)"
          >
            <i
              v-show="item.isRequired && !item.validate"
              slot="suffix"
              :title="item.errorMsg"
              class="el-input__icon el-icon-warning"
            />
          </el-input>
        </template>
        <!-- 自定义slot -->
        <template v-else-if="item.slotName">
          <!-- {{ row.isRead }} -->
          <slot
            :slotScope="scope"
            :name="item.slotName"
          />
        </template>
        <!-- 非编辑和自定义（可以自定义prop  主要预防下拉框保存的字段和显示字段不一致） -->
        <span v-else>{{ item.customProp?scope.row[item.customProp]:scope.row[item.prop] }}</span>
        <template slot="header">
          <slot name="header" />
        </template>
      </template>
    </el-table-column>
  </el-table>
</template>
<script lang="ts">
/* 可编辑行的表格 */
// 保存时候返回当前行的数据row
// 验证row.error为true的话，不可保存
// row.edit 是当前行是否可编辑的标识
// 编辑行调用组件的  editRow(row)  方法；
// 取消编辑行调用组件的  cancelRow（row） 方法
// 清除验证 调用  clearValidate（）方法
// 触发验证 调用 saveValidate（）方法

// 表头及数据字段tableColumn数组
/*
 *{
 * width:'120'  列宽
 * fixed: true || 'left' || 'right'
 * align:'right' 列水平对齐方式
 * min-width:'120'  列最小宽度
 * prop: 'sort',   列对应的字段 （*必传）
 * label: '排序号',  列对应的头 （*必传）
 * edit: true,   当前列是否可编辑
 * unSortable:true    不需要排序
 * maxLength: 8,  可编辑的话最大长度
 * isRequired: true,   验证是否必须
 * pattern: /^\d{1,8}$/,  验证正则
 * errorMsg: '请输入1到8位纯数字排序号',   验证不通过错误信息
 * validateType: 'number'   验证类型（目前只有number/select）
 * selectList : []    下拉列表 （validateType=select  必传）
 * className:''  自定义列的类名，控制列样式
 * slotName:''   自定义slot进表格
 * }
 */

import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
@Component({
  name: 'MTable'
})
export default class extends Vue {
  @Prop({ default: [] }) private data!: any[]; // 表格数据
  @Prop({ required: true }) private tableColumn!: any[];
  @Prop({ default: false }) private showIndex!: boolean; // 是否显示序号列
  @Prop({ default: false }) private showSelection!: boolean; // 是否显示选择框
  @Prop({ default: '100000' }) private maxHeight!: string; // 最大高度  超出滚动
  @Prop({ default: '暂无数据' }) private emptyText!: string; //
  @Prop({ default: '' }) private rowKey!: string | number; //
  @Prop({ default: false }) private border!: boolean; // 边框
  @Prop({ default: false }) private stripe!: boolean; // 条纹
  @Prop({ default: false }) private highlightCurrentRow!: boolean; // 条纹

  private operateRow = {};

  @Watch('tableColumn') // 列的验证  默认验证通过
  private onTableColumn(v: any[]) {
    v.map(x => {
      this.$set(x, 'validate', true)
    })
  }
  @Watch('data') // 表格数据做处理
  onDataChange(v: any[]) {
    v.map(x => {
      this.$set(x, 'error', false) // 控制整行是否有验证错误  默认正确
    })
  }
  mounted() {
    // 初始化 全部列默认验证  watch也要写，表格可能动态变化
    this.clearValidate()
  }
  // 清除验证
  clearValidate() {
    // 全部列默认验证(全部默认通过)
    this.tableColumn.map(x => {
      this.$set(x, 'validate', true)
    })
  }
  // 编辑这一行数据  把当前字段源数据保存
  editRow(row: any) {
    // 上一次编辑过如果没有保存，点击当前行，复原数据
    if (this.operateRow) {
      this.cancelRow(this.operateRow)
    } else {
      this.operateRow = row
    }
    // 当前一行可编辑，其他行不可编辑
    this.data.map(x => {
      this.$set(x, 'edit', false)
    })
    this.$set(row, 'edit', true)

    // 过滤出对应的prop  保存编辑前数据
    let keys: any[] = []
    this.tableColumn.map(x => {
      keys.push(x.prop)
    })
    keys.map(x => {
      this.$set(row, 'old' + x, row[x])
    })
  }
  // 取消编辑行  复原数据
  cancelRow(row: any) {
    row.edit = false
    // 过滤出对应的prop
    let keys: any[] = []
    this.tableColumn.map(x => {
      keys.push(x.prop)
    })
    keys.map(x => {
      row[x] = row['old' + x]
    })

    this.clearValidate()
  }
  // input框change  触发验证
  handleChange(row: any, item: any) {
    // 是必须
    if (item.isRequired) {
      // 没有验证规则 验证是否为空
      if (!item.pattern) {
        // 空
        if (!row[item.prop]) {
          item.validate = false
        } else {
          item.validate = true
        }
        // 验证规则不通过
      } else if (!item.pattern.test(row[item.prop])) {
        // 如果是数字类型的，只能输入数字
        if (item.validateType === 'number') {
          row[item.prop] = ''
        }
        item.validate = false
        // 通过
      } else {
        item.validate = true
      }
      // 不必须
    } else {
      item.validate = true
    }

    // 验证整行
    this.validateRow(row)
  }
  // 验证整行
  validateRow(row: any) {
    row.error = false
    this.tableColumn.map(x => {
      // 有一列没通过验证，整行都没有通过
      if (!x.validate) {
        row.error = true
      }
    })
  }
  // 保存校验（调用此方法，随时可以触发校验）
  saveValidate(row) {
    this.tableColumn.forEach(v => {
      this.handleChange(row, v)
    })
  }
  // 清楚表头排序
  clearSort() {
    (this.$refs.tableRef as any).clearSort()
  }
  // 选择框事件触发
  handleSelection(v) {
    this.$emit('selection-change', v)
  }
  // 清空用户的选择
  clearSelection() {
    (this.$refs.tableRef as any).clearSelection()
  }
  // 当前行选中
  handleCurrentChange(v) {
    this.$emit('current-change', v)
  }
}
</script>
